package cn.siat.gene.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cn.siat.common.core.exception.ServiceException;
import cn.siat.common.core.utils.DateUtils;
import cn.siat.common.core.web.controller.BaseController;
import cn.siat.common.core.web.domain.AjaxResult;
import cn.siat.common.core.web.page.TableDataInfo;
import cn.siat.common.log.annotation.Log;
import cn.siat.common.log.enums.BusinessType;
import cn.siat.common.security.utils.SecurityUtils;
import cn.siat.gene.domain.*;
import cn.siat.gene.domain.vo.ProgrammeVO;
import cn.siat.gene.domain.dto.ProgrammeQueryParam;
import cn.siat.gene.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.Serializable;
import java.util.*;

/**
 * @Description: 方案信息
 * @Author: Administrator
 * @Date: 2022-10-22
 * @Version: V1.0
 */
@Api(tags = "方案信息")
@RestController
@RequestMapping("/programme")
@Slf4j
public class ProgrammeController extends BaseController {
    @Autowired
    private IProgrammeService programmeService;
    @Autowired
    private IProgrammeStateService programmeStateService;
    @Autowired
    private SequenceService sequenceService;
    @Autowired
    private DesignService designService;
    @Autowired
    private AssociatedMoleculeService associatedMoleculeService;
    @Autowired
    private BioinformaticsPipelineService bioinformaticsPipelineService;
    @Autowired
    private FeatureService featureService;
    @Autowired
    private IDesignTBProjectMembersService designTBProjectMembersService;

    @Value("${params.maxAnalyseRunCount}")
    private Integer maxRunCount;

    /**
     * 分页列表查询
     *
     * @return
     */
    @Log(title = "方案查询", businessType = BusinessType.VIEWED)
    @ApiOperation(value = "方案查询", notes = "方案查询")
    @GetMapping(value = "/list")
    public TableDataInfo queryPageList(ProgrammeQueryParam queryParams) {
        startPage();
        List<ProgrammeVO> pageList = programmeService.queryPageList(queryParams);
        return getDataTable(pageList);
    }

    /**
     * 通过模板创建方案
     *
     * @param programme
     * @return
     */
    @Log(title = "新建模板方案", businessType = BusinessType.INSERT)
    @ApiOperation(value = "新建模板方案", notes = "新建模板方案")
    @PostMapping("/createByTemplate")
    public AjaxResult createByTemplate(@RequestBody Programme programme) {
        Map<String, String> map = programmeService.createByTemplate(programme);
        String fileName = map.get("fileName");
        String programmeId = map.get("programmeId");
        try {
            sequenceService.cutSequenceFile(new String[]{fileName}, programmeId);
        } catch (IOException e) {
            throw new ServiceException("切分序列失败!");
        }
        return AjaxResult.success("操作成功", programmeId);
    }


    @Log(title = "新建空白方案", businessType = BusinessType.INSERT)
    @ApiOperation(value = "新建空白方案", notes = "新建空白方案")
    @PostMapping(value = "/createBlank")
    public AjaxResult createBlank(@RequestBody Programme programme) {
        boolean exists = programmeService.checkName(programme.getProgrammeName(),null);
        if (exists) {
            return AjaxResult.error("操作失败！当前方案已存在");
        } else {
            return programmeService.createBlank(programme);
        }
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @Log(title = "方案信息-删除", businessType = BusinessType.DELETE)
    @ApiOperation(value = "方案信息-删除", notes = "方案信息-删除")
    @DeleteMapping(value = "/deleteBatch")
    public AjaxResult deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
        String[] programmeIds = ids.split(",");
        int count = 0;
        for (int i = 0; i < programmeIds.length; i++) {
            Programme programme = programmeService.getById(programmeIds[i]);
            if (programme == null) {
                count++;
            }
        }
        if (count != 0) {
            return AjaxResult.error("当前方案不存在");
        } else {
            programmeService.deleteBatch(ids);
            return AjaxResult.success("操作成功");
        }


    }


    /**
     * 项目中移除方案
     */
    @DeleteMapping("/project/{id}")
    public AjaxResult removeProgrammeInProject(@PathVariable String id) {
        return toAjax(programmeService.removeProgrammeInProjectById(id));
    }

    /**
     * 分享方案
     *
     * @author zhanggj@hearglobal.com
     * @date 2022.11.2 15:41
     * @version 0.0.1
     */
    @Log(title = "分享方案", businessType = BusinessType.INSERT)
    @ApiOperation(value = "分享方案", notes = "分享方案")
    @PostMapping(value = "/share-programme")
    @Async
    public AjaxResult shareProgramme(@RequestBody Programme programme) {

        try {
            programmeService.shareProgramme(programme);
            return AjaxResult.success("分享成功");
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 修改后的分享方案
     */
    @Log(title = "分享方案", businessType = BusinessType.INSERT)
    @ApiOperation(value = "分享方案", notes = "分享方案")
    @PostMapping(value = "/share")
    public AjaxResult share(@RequestBody Programme programme) {
        programmeService.share(programme);
        return AjaxResult.success("操作成功");
    }

    /**
     * 处理分享方案
     *
     * @author zhanggj@hearglobal.com
     * @date 2022.11.2 15:41
     * @version 0.0.1
     */
    @Log(title = "处理分享方案", businessType = BusinessType.INSERT)
    @ApiOperation(value = "处理分享方案", notes = "处理分享方案")
    @PostMapping(value = "/dispose-share-programme")
    public AjaxResult disposeShareProgramme(@RequestBody Information information) {
        String id = information.getId();
        Integer informationState = information.getInformationState();
        String newProgrammeName = information.getProgrammeName();
        Map<String, String> map = programmeService.disposeShareProgramme(id, informationState, newProgrammeName);
        if (map != null) {
            String fileName = map.get("fileName");
            String programmeId = map.get("programmeId");
            try {
                sequenceService.cutSequenceFile(new String[]{fileName}, programmeId);
            } catch (IOException e) {
                throw new ServiceException("切分序列失败!");
            }
            return AjaxResult.success("操作成功", programmeId);
        }
        return AjaxResult.success("操作成功");
    }

    /**
     * 获取处理分享方案
     *
     * @author zhanggj@hearglobal.com
     * @date 2022.11.2 15:41
     * @version 0.0.1
     */
    @Log(title = "获取处理分享方案", businessType = BusinessType.INSERT)
    @ApiOperation(value = "获取处理分享方案", notes = "获取处理分享方案")
    @PostMapping(value = "/get-dispose-share-programme")
    public TableDataInfo getDisposeShareProgramme() {

        List<Information> disposeShareProgramme = programmeService.getDisposeShareProgramme();
        return getDataTable(disposeShareProgramme);
    }

    /**
     * 获取处理分享方案
     *
     * @author zhanggj@hearglobal.com
     * @date 2022.11.2 15:41
     * @version 0.0.1
     */
    @Log(title = "克隆方案", businessType = BusinessType.INSERT)
    @ApiOperation(value = "克隆方案", notes = "克隆方案")
    @PostMapping(value = "/clone")
    public AjaxResult cloneProgramme(@RequestBody Programme programme) {
        programmeService.cloneProgramme(programme);
        return AjaxResult.success("操作成功");
    }

    /**
     * 添加
     *
     * @param programme
     * @return
     */
    @Log(title = "方案信息-添加", businessType = BusinessType.INSERT)
    @ApiOperation(value = "方案信息-添加", notes = "方案信息-添加")
    @PostMapping(value = "/add")
    public AjaxResult add(@RequestBody Programme programme) {
//        QueryWrapper queryWrapper = new QueryWrapper();
//        queryWrapper.eq("number", programme.getProgrammeNumber());
//        if (programmeService.count(queryWrapper) > 0) {
//            return AjaxResult.error("方案编码已存在");
//        }
        // 方案编码
        programme.setProgrammeNumber(DateUtils.dateTimeNow());
        programme.setCreateTime(new Date());
        programme.setCreateStaffNo(SecurityUtils.getUserId());
        programme.setPossessStaff(SecurityUtils.getUserId());
        programme.setUpdateTime(new Date());
        programme.setUpdateStaffNo(SecurityUtils.getUserId());
        // 获取未打包状态ID
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("programme_number", "FA_STATUS_001"); // 未打包标识
        ProgrammeState state = programmeStateService.getOne(queryWrapper, false);
        if (state != null) {
            programme.setStateId(state.getId());
        }
        programme.setSequenceLengthToShow(30000);
        programmeService.save(programme);
        return AjaxResult.success("操作成功");
    }

    /**
     * 编辑
     *
     * @param programme
     * @return
     */
    @Log(title = "方案信息-编辑", businessType = BusinessType.UPDATE)
    @ApiOperation(value = "方案信息-编辑", notes = "方案信息-编辑")
    @PutMapping(value = "/edit")
    public AjaxResult edit(@RequestBody Programme programme) {
//        QueryWrapper queryWrapper = new QueryWrapper();
//        queryWrapper.eq("number", programme.getProgrammeNumber());
//        queryWrapper.ne("id", programme.getId());
//        if (programmeService.count(queryWrapper) > 0) {
//            return AjaxResult.error("方案编码已存在");
//        }
        programmeService.editProgramme(programme);
        return AjaxResult.success("操作成功");

    }

    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @Log(title = "方案信息-通过id删除", businessType = BusinessType.DELETE)
    @ApiOperation(value = "方案信息-通过id删除", notes = "方案信息-通过id删除")
    @DeleteMapping(value = "/delete")
    public AjaxResult delete(@RequestParam(name = "id", required = true) String id) {
        Programme programme = programmeService.getById(id);
        if (programme == null) {
            throw new ServiceException("删除方案不存在！");
        }
        //清理关联装置设计
        if (StringUtils.hasLength(programme.getDesignProjectId())) {
            designService.clearDesign(id);
        }
        programmeService.removeById(id);
        return AjaxResult.success("操作成功");
    }


    /**
     * 通过id查询
     *
     * @param id
     * @return
     */
    @ApiOperation(value = "方案信息-通过id查询", notes = "方案信息-通过id查询")
    @GetMapping(value = "/queryById")
    @Transactional
    public AjaxResult queryById(@RequestParam(name = "id", required = true) String id) {
        Programme programme = programmeService.getById(id);
        if (programme == null) {
            return AjaxResult.error("未找到对应数据");
        }
        if (programme.getMolecularPack() == null) {
            programme.setMolecularPack(new HashMap<>());
        }
        //更新最后浏览方案时间
        programmeService.updateById(new Programme().setId(id).setViewedTime(new Date()));
        return AjaxResult.success(programme);
    }

    /**
     * 检查是否有查看方案权限
     *
     * @param id
     * @return
     */
    @GetMapping(value = "/checkById")
    public AjaxResult checkById(@RequestParam(name = "id", required = true) String id) {
        Programme programme = programmeService.getById(id);
        if (programme == null) {
            return AjaxResult.error("未找到对应方案!");
        }
        return AjaxResult.success(SecurityUtils.getUserId().equals(programme.getPossessStaff()));
    }


    @ApiOperation(value = "方案信息-通过id查询", notes = "方案信息-通过id查询")
    @GetMapping(value = "/getProgrammeAndSequence")
    @Transactional
    public AjaxResult getProgrammeAndSequence(@RequestParam(name = "id", required = true) String id, Integer removeTemFeature) {
        Programme programme = programmeService.getById(id);
        if (programme == null) {
            return AjaxResult.error("未找到对应数据");
        }
        List<Sequence> sequenceList = sequenceService.listSequence(new Sequence().setProgrammeId(id));
        programme.setSequenceList(sequenceList);
        return AjaxResult.success(programme);
    }

    /**
     * 获取全部用户
     *
     * @return
     */
    @GetMapping("/user/list")
    public AjaxResult getAllUser() {
        List<Map<String, String>> list = programmeService.getAllUser();
        return AjaxResult.success(list);
    }


    /**
     * 查询最近浏览10条方案
     */
    @GetMapping("/listViewed")
    public AjaxResult listViewedProgrammes() {
        return AjaxResult.success(programmeService.selectViewedProgrammes());
    }

    /**
     * 校验名称(已存在返回true)
     *
     * @return
     */
    @GetMapping("/checkName")
    public AjaxResult checkName(String programmeName, String id) {
        Boolean isExist = programmeService.checkName(programmeName, id);
        return AjaxResult.success(isExist);
    }

    /**
     * 模拟发送至云实验室
     *
     * @param params
     * @return
     */
    @PostMapping("/toLab")
    public AjaxResult toLab(@RequestBody Map<String, String> params) {
//        System.err.println(params);

        programmeService.toLab(params);
        return AjaxResult.success("发送成功!");
    }


    /**
     * 执行分析程序
     *
     * @param params
     * @return
     */
    @PostMapping(value = "/blast2")
    public AjaxResult blast2(@RequestBody Map<String, String> params) {
        //查看正在运行数
        QueryWrapper<Programme> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("create_staff_no", SecurityUtils.getUserId())
                .eq("analyse_state", 0);
        long count = programmeService.count(queryWrapper);
        if (count >= maxRunCount) {
            throw new ServiceException("不能有超过" + maxRunCount + "条分析程序同时执行！");
        }
        programmeService.updateById(new Programme()
                .setId(params.get("programmeId"))
                .setAnalyseState(0)
                .setProgrammeState(0));
        bioinformaticsPipelineService.blast2(params);
        return AjaxResult.success();
    }

    /**
     * 检查分析运行状态
     *
     * @param id
     * @return
     */
    @GetMapping("checkAnalyseState")
    public AjaxResult checkAnalyseState(String id) {
        Programme programme = programmeService.getById(id);
        return AjaxResult.success(programme.getAnalyseState());
    }

    /**
     * 基因表达预测
     *
     * @param params
     * @return
     * @throws IOException
     */
    @PostMapping(value = "/geneExpression")
    public ResponseEntity<?> geneExpression(@RequestBody Map<String, String> params) {

        return bioinformaticsPipelineService.geneExpression(params);
    }


    /**
     * 查询非当前项目的方案
     *
     * @param projectId
     * @return
     */
    @GetMapping("/listNoProjectProgrammes")
    public AjaxResult listNoProjectProgrammes(String projectId) {
        return AjaxResult.success(programmeService.listNoProjectProgrammes(projectId));
    }

    /**
     * 更改方案归属项目
     */
    @PutMapping("/updateProject")
    public AjaxResult updateProject(@RequestBody Map<String, Object> map) {
        ArrayList<String> ids = (ArrayList) map.get("ids");
        String projectId = (String) map.get("projectId");
        String projectName = (String) map.get("projectName");
        Boolean flag = designTBProjectMembersService.isProjectMember(projectId);
        if (!flag) {
            throw new ServiceException("没有查看该项目权限");

        }
        return programmeService.updateProject(ids.toArray(new String[0]), projectId, projectName);
    }

    /**
     * 获取方案列表创建人筛选项
     */
    @GetMapping("/listCreateStaff")
    public AjaxResult listProgrammeCreateStaff() {
        return AjaxResult.success(programmeService.selectProgrammeCreateStaffList());
    }

    /**
     * 编辑
     *
     * @param programme
     * @return
     */
    @Log(title = "方案状态-修改", businessType = BusinessType.UPDATE)
    @ApiOperation(value = "方案状态-修改", notes = "方案状态-修改")
    @PutMapping(value = "/updateExamineState")
    public AjaxResult updateExamineState(@RequestBody Programme programme) {
//        UpdateWrapper updateWrapper = new UpdateWrapper();
//        updateWrapper.eq("id", programme.getId());
//        updateWrapper.set("programme_examine_state", programme.getProgrammeExamineState());
        programmeService.updateExamineState(programme);
        return AjaxResult.success("操作成功");

    }
}
